package com.andy.sqlSession;

import com.andy.pojo.Configuration;
import com.andy.pojo.MappedStatement;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;
    private Executor executor = new SimpleExecutor();

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... param) throws Exception{
        List<E> resultList = executor.query(configuration, configuration.getMappedStatement(statementId), param);
        return resultList;
    }

    @Override
    public <T> T selectOne(String statementId, Object... param) throws Exception {
        List<T> resultList = selectList(statementId, param);
        if(resultList.size()==1){
            return resultList.get(0);
        }else{
            throw new RuntimeException("查询结果不为1条");
        }
    }

    @Override
    public int insert(String statementId, Object... param) throws Exception {
        return executor.update(configuration, configuration.getMappedStatement(statementId), param);
    }

    @Override
    public int update(String statementId, Object... param) throws Exception {
        return executor.update(configuration, configuration.getMappedStatement(statementId), param);
    }

    @Override
    public int delete(String statementId, Object... param) throws Exception {
        return executor.update(configuration, configuration.getMappedStatement(statementId), param);
    }

    @Override
    public void close() throws SQLException {
        executor.close();
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        T mapper = (T)Proxy.newProxyInstance(mapperClass.getClassLoader(),new Class[]{ mapperClass},new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取接口路径对应nameSpace
                String className = mapperClass.getName();
                //获取方法名对应id
                String methodName = method.getName();
                //拼接获得statement的key
                String key = className+"."+methodName;
                //拿到statement
                MappedStatement mappedStatement = configuration.getMappedStatement(key);

                //拿到了sql的类型(select,insert,update,delete)
                String sqlType = mappedStatement.getSqlType();
                //查询类型
                if("select".equals(sqlType)){
                    //如果出参用了泛型，则认为是查询列表
                    if(method.getGenericReturnType() instanceof ParameterizedType){
                        return selectList(key,args);
                    }else{//否则认为是查询单个
                        return selectOne(key,args);
                    }
                }else if("insert".equals(sqlType)){
                    return insert(key,args);
                }else if("update".equals(sqlType)){
                    return update(key,args);
                }else if("delete".equals(sqlType)){
                    return delete(key,args);
                }

                return null;
            }
        });

        return mapper;
    }
}
